import React, {
  useRef,
  useState,
  useEffect,
  useContext,
  forwardRef,
  useImperativeHandle,
} from 'react'
import { Form, Input, Table } from 'antd'

import type { InputRef, FormInstance } from 'antd'
import type { EditableRowProps, EditableCellProps, RefProps, FiledTableProps } from './type'

import './index.less'

const EditableContext = React.createContext<FormInstance>({} as FormInstance)

const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
  const [form] = Form.useForm()
  return (
    <Form form={form} component={false}>
      <EditableContext.Provider value={form}>
        <tr {...props} />
      </EditableContext.Provider>
    </Form>
  )
}

const EditableCell: React.FC<EditableCellProps> = ({
  editable,
  children,
  dataIndex,
  record,
  handleSave,
  rules,
  ...restProps
}) => {
  const [editing, setEditing] = useState(false)
  const inputRef = useRef<InputRef>(null)
  const form = useContext(EditableContext)
  useEffect(() => {
    if (editing) {
      inputRef.current?.focus()
    }
  }, [editing])

  const toggleEdit = () => {
    setEditing(!editing)
    form.setFieldsValue({
      [dataIndex]: record[dataIndex],
    })
  }

  const save = async () => {
    try {
      const values = await form.validateFields()
      toggleEdit()
      if (record.error) {
        delete record.error
      }
      handleSave({ ...record, ...values })
    } catch (error) {
      handleSave({ ...record, error })
    }
  }
  let childNode = children
  if (editable) {
    childNode = editing ? (
      <Form.Item style={{ margin: 0 }} name={dataIndex} rules={rules || []}>
        <Input ref={inputRef} onPressEnter={save} onBlur={save} />
      </Form.Item>
    ) : (
      <div className="editable-cell-value-wrap" style={{ paddingRight: 24 }} onClick={toggleEdit}>
        {children}
      </div>
    )
  }
  // @ts-ignore
  return <td {...restProps}>{childNode}</td>
}

const FiledTable = forwardRef<RefProps, FiledTableProps>((props, ref) => {
  const {
    uniqueKey = 'id',
    dataSource: propDataSource = [],
    columns: propsColumns,
    pagination: {
      total,
      current,
      pageSize,
      onChange,
      size = 'default',
      showSizeChanger = true,
      showQuickJumper = true,
    } = {},
    onFieldSave,
    ...rest
  } = props
  const [dataSource, setDataSource] = useState(propDataSource)
  const [editable, setEditable] = useState(false)

  useEffect(() => {
    setDataSource(propDataSource)
  }, [propDataSource])

  useEffect(() => {
    setEditable(propsColumns.some(col => col.editable))
  }, [propsColumns])

  useImperativeHandle(ref, () => ({
    getDataSource: () => dataSource,
  }))

  const handleSave = (row: { [name: string]: any }, index: number) => {
    const newData = [...dataSource]
    // const index = newData.findIndex(item => row[uniqueKey] === item[uniqueKey])
    const item = newData[index]
    newData.splice(index, 1, { ...item, ...row })
    setDataSource(newData)
    onFieldSave?.(row, newData)
  }

  const columns = editable
    ? propsColumns?.map(col => {
        if (!col?.editable) {
          return col
        }
        return {
          ...col,
          onCell: (record: any, idx: number) => ({
            record,
            editable: col.editable,
            dataIndex: col.dataIndex,
            title: col.title,
            rules: typeof col.rules === 'function' ? col?.rules(record) : col.rules,
            handleSave: (record: any) => handleSave(record, idx),
          }),
        }
      })
    : propsColumns

  const components = { body: { row: EditableRow, cell: EditableCell } }

  return (
    <Table
      {...rest}
      columns={columns as FiledTableProps['columns']}
      dataSource={dataSource}
      components={editable ? components : undefined}
      className="field-table"
      rowClassName={() => 'editable-row'}
      rowSelection={props.rowSelection ? props.rowSelection : undefined}
      pagination={
        props.pagination
          ? {
              total,
              size,
              current,
              pageSize,
              onChange,
              showSizeChanger,
              showQuickJumper,
              position: ['bottomRight'],
            }
          : false
      }
    />
  )
})

FiledTable.displayName = 'FiledTable'

export default FiledTable
